#include "lru_replacer.h" // °üº¬ LRUReplacer ÀàµÄÉùÃ÷

// ¹¹Ôìº¯ÊýÊµÏÖ
LRUReplacer::LRUReplacer(size_t num_pages) {
    max_size_ = num_pages;
    // LRUlist_ ºÍ LRUhash_ »á×Ô¶¯Ä¬ÈÏ¹¹ÔìÎª¿Õ
}

// Îö¹¹º¯ÊýÊµÏÖ
LRUReplacer::~LRUReplacer() = default;

/**
 * @brief Ê¹ÓÃ LRU ²ßÂÔÑ¡ÔñÒ»¸öÎþÉüÖ¡¡£
 * @param[out] frame_id id of frame that was removed, nullptr if no victim was found
 * @return true if a victim frame was found, false otherwise
 */
bool LRUReplacer::Victim(frame_id_t *frame_id) {
    // C++17 std::scoped_lock
    // ËüÄÜ¹»±ÜÃâËÀËø·¢Éú£¬Æä¹¹Ôìº¯ÊýÄÜ¹»×Ô¶¯½øÐÐÉÏËø²Ù×÷£¬Îö¹¹º¯Êý»á¶Ô»¥³âÁ¿½øÐÐ½âËø²Ù×÷£¬±£Ö¤Ïß³Ì°²È«¡£
    std::scoped_lock lock{latch_};

    // Todo:
    // ÀûÓÃlru_replacerÖÐµÄLRUlist_,LRUhash_ÊµÏÖLRU²ßÂÔ
    // Ñ¡ÔñºÏÊÊµÄframeÖ¸¶¨ÎªÌÔÌ­Ò³Ãæ,¸³Öµ¸ø*frame_id

    // Èç¹û LRU ÁÐ±íÎª¿Õ£¬ËµÃ÷Ã»ÓÐ¿ÉÒÔÌÔÌ­µÄÖ¡
    if (LRUlist_.empty()) {
        if (frame_id != nullptr) {
            *frame_id = -1; // ÉèÖÃÎªÎÞÐ§ ID£¬¼ÙÉè -1 ÊÇÒ»¸öÎÞÐ§µÄ frame_id
        }
        return false;
    }

    // LRU ²ßÂÔ£ºÌÔÌ­×î¾ÃÎ´Ê¹ÓÃµÄÖ¡£¬¼´Á´±íÎ²²¿µÄÔªËØ
    if (frame_id != nullptr) {
        *frame_id = LRUlist_.back(); // »ñÈ¡Î²²¿ÔªËØ×÷ÎªÎþÉüÖ¡µÄ ID
    }
    LRUlist_.pop_back(); // ´ÓÁ´±íÖÐÒÆ³ý¸ÃÔªËØ

    // ´Ó¹þÏ£±íÖÐÒÆ³ý¶ÔÓ¦µÄÓ³Éä
    LRUhash_.erase(*frame_id);

    return true;
}

/**
 * @brief ¹Ì¶¨Ò»¸öframe, ±íÃ÷Ëü²»Ó¦¸Ã³ÉÎªvictim£¨¼´ÔÚreplacerÖÐÒÆ³ý¸Ãframe_id£©
 * @param frame_id the id of the frame to pin
 */
void LRUReplacer::Pin(frame_id_t frame_id) {
    std::scoped_lock lock{latch_};
    // Todo:
    // ¹Ì¶¨Ö¸¶¨idµÄframe
    // ÔÚÊý¾Ý½á¹¹ÖÐÒÆ³ý¸Ãframe

    // ÔÚ¹þÏ£±íÖÐ²éÕÒ¸ÃÖ¡
    auto it = LRUhash_.find(frame_id);
    if (it != LRUhash_.end()) {
        // Èç¹û¸ÃÖ¡´æÔÚÓÚ replacer ÖÐ£¨¼´Ëüµ±Ç°ÊÇ unpinned ×´Ì¬£©£¬Ôò½«ÆäÒÆ³ý
        LRUlist_.erase(it->second); // ´ÓÁ´±íÖÐÒÆ³ý£¨Ê¹ÓÃ´æ´¢µÄµü´úÆ÷ÊµÏÖ O(1) ÒÆ³ý£©
        LRUhash_.erase(it);         // ´Ó¹þÏ£±íÖÐÒÆ³ý¶ÔÓ¦µÄÌõÄ¿
    }
    // Èç¹û¸ÃÖ¡²»ÔÚ replacer ÖÐ£¬ËµÃ÷ËüÒÑ¾­±»¹Ì¶¨£¨pinned£©»òÕß´ÓÎ´±» unpin ¹ý£¬ÎÞÐè²Ù×÷¡£
}

/**
 * @brief È¡Ïû¹Ì¶¨Ò»¸öframe, ±íÃ÷Ëü¿ÉÒÔ³ÉÎªvictim£¨¼´½«¸Ãframe_idÌí¼Óµ½replacer£©
 * @param frame_id the id of the frame to unpin
 */
void LRUReplacer::Unpin(frame_id_t frame_id) {
    // Todo:
    // Ö§³Ö²¢·¢Ëø
    // Ñ¡ÔñÒ»¸öframeÈ¡Ïû¹Ì¶¨
    std::scoped_lock lock{latch_};

    // ÔÚ¹þÏ£±íÖÐ²éÕÒ¸ÃÖ¡
    auto it = LRUhash_.find(frame_id);
    if (it != LRUhash_.end()) {
        // Èç¹û¸ÃÖ¡ÒÑ¾­´æÔÚÓÚ replacer ÖÐ£¨¼´ËüÖ®Ç°ÊÇ unpinned ×´Ì¬£©£¬
        // Ôò½«Æä´Óµ±Ç°Î»ÖÃÒÆ³ý£¬²¢ÒÆ¶¯µ½Á´±íÍ·²¿£¬±íÊ¾×î½üÊ¹ÓÃ
        LRUlist_.erase(it->second); // ´Óµ±Ç°Î»ÖÃÒÆ³ý
        LRUlist_.push_front(frame_id); // ²åÈëµ½Á´±íÍ·²¿£¨±íÊ¾×î½üÊ¹ÓÃ£©
        it->second = LRUlist_.begin(); // ¸üÐÂ¹þÏ£±íÖÐ¶ÔÓ¦µÄµü´úÆ÷
    } else {
        // Èç¹û¸ÃÖ¡²»ÔÚ replacer ÖÐ£¨¼´ËüÖ®Ç°ÊÇ pinned ×´Ì¬»òÊ×´Î unpin£©£¬
        // ÔòÖ±½Ó½«Æä²åÈëµ½Á´±íÍ·²¿£¬²¢Ìí¼Óµ½¹þÏ£±í
        // ×¢Òâ£ºÕâÀïÐèÒª¼ì²éÊÇ·ñ³¬¹ý max_size_£¬µ«Í¨³£Õâ¸öÂß¼­ÓÉ BufferPoolManager ¹ÜÀí
        // Èç¹û BufferPoolManager È·±£ÁË²»»á³¬¹ýÈÝÁ¿£¬ÕâÀïÖ±½ÓÌí¼Ó¼´¿É¡£
        // Èç¹ûÐèÒªÔÚ´Ë´¦ÏÞÖÆ´óÐ¡£¬¿ÉÒÔÌí¼Ó if (LRUlist_.size() < max_size_) { ... }
        LRUlist_.push_front(frame_id); // ²åÈëµ½Á´±íÍ·²¿
        LRUhash_[frame_id] = LRUlist_.begin(); // ½«ÐÂµÄÖ¡ºÍÆäµü´úÆ÷Ìí¼Óµ½¹þÏ£±í
    }
}

/** @return replacerÖÐÄÜ¹»victimµÄÊýÁ¿ */
size_t LRUReplacer::Size() {
    // Todo:
    // ¸ÄÐ´return size
    std::scoped_lock lock{latch_};
    // ·µ»Øµ±Ç° LRU ÁÐ±íÖÐ£¨¼´¿ÉÒÔ±»ÌÔÌ­µÄ£©Ö¡µÄÊýÁ¿
    return LRUlist_.size();
}

